package com.tinyseed.emcp.api.exception.service;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.tinyseed.emcp.api.app.common.DateUtil;
import com.tinyseed.emcp.api.basicdata.model.OrganizeOutputDTO;
import com.tinyseed.emcp.api.basicdata.service.OrganizeService;
import com.tinyseed.emcp.api.exception.bean.ExceptionInfoInputDTO;
import com.tinyseed.emcp.api.exception.bean.ExceptionInfoOutputDTO;
import com.tinyseed.emcp.api.exception.entity.DailyExceptionInfo;
import com.tinyseed.emcp.api.exception.entity.ExceptionInfo;
import com.tinyseed.emcp.api.exception.repository.DailyExceptionInfoRepository;
import com.tinyseed.emcp.api.exception.repository.ExceptionInfoRepository;
import com.tinyseed.emcp.api.exception.state.NewState;
import com.tinyseed.emcp.api.maintenance.domain.MaintenanceInfo;
import com.tinyseed.emcp.api.maintenance.service.MaintenanceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
@Slf4j
public class ExceptionInfoServiceImpl implements ExceptionInfoService {

    @Autowired
    private ExceptionInfoRepository exceptionInfoRepository;

    @Autowired
    private DailyExceptionInfoRepository dailyExceptionInfoRepository;

    @Autowired
    private MaintenanceService maintenanceService;

    @Autowired
    private OrganizeService organizeService;

    @Override
    public List<ExceptionInfoOutputDTO> getList() {

        Pageable pageable = PageRequest.of(0, 15);

        Page<ExceptionInfo> exceptionInfos = exceptionInfoRepository.findAll(pageable);

        /*转换格式为outputdto*/
        List<ExceptionInfoOutputDTO> exceptionInfoOutputDTOS = new ArrayList<>();
        exceptionInfos.getContent().forEach(temp -> {
            ExceptionInfoOutputDTO enterpriseOutputDTO1 = new ExceptionInfoOutputDTO();
            BeanUtils.copyProperties(temp, enterpriseOutputDTO1);
            exceptionInfoOutputDTOS.add(enterpriseOutputDTO1);
        });
        return exceptionInfoOutputDTOS;
    }

    @Override
    public Page getList(ExceptionInfoInputDTO inputDTO, int size, int current) {
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");

        return exceptionInfoRepository.findAll((Root<ExceptionInfo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) -> {
            //必须用 List<Predicate>，否则不能多条件查询

            List<Predicate> list = new ArrayList<>();
            Optional.ofNullable(inputDTO.getCreateTimeStart()).flatMap(startTime -> Optional.ofNullable(inputDTO.getCreateTimeEnd())).ifPresent(endTime -> {
                Predicate timeQuery = criteriaBuilder.and(criteriaBuilder.between(root.get("createTime"), DateUtil.parseDateUTCTime(inputDTO.getCreateTimeStart()), DateUtil.parseDateUTCTime(inputDTO.getCreateTimeEnd())));
                list.add(timeQuery);
            });

            Optional.ofNullable(inputDTO.getEnterpriseName()).ifPresent(name -> {
                Predicate enterpriseNameQuery = criteriaBuilder.and(criteriaBuilder.like(root.get("enterpriseName"), "%" + inputDTO.getEnterpriseName() + "%"));
                list.add(enterpriseNameQuery);
            });
            Optional.ofNullable(inputDTO.getEventType()).ifPresent(item -> {
                Predicate eventTypeQuery = criteriaBuilder.and(criteriaBuilder.like(root.get("eventType"), inputDTO.getEventType()));
                list.add(eventTypeQuery);
            });
            Optional.ofNullable(inputDTO.getOrganizeId()).ifPresent(id -> {
                List<OrganizeOutputDTO> o = organizeService.getOrganizeIdListByid(Long.valueOf(id));
                CriteriaBuilder.In<Object> in = criteriaBuilder.in(root.get("organizeName"));
                o.forEach(item->{
                    in.value(item.getOrganizeName());
                });
                Predicate temp = criteriaBuilder.and(in);
                list.add(temp);
            });

            Predicate[] p = list.toArray(new Predicate[0]);
            return criteriaBuilder.and(p);
        }, PageRequest.of(current - 1, size, sort));

    }

    @Override
    public void createMTInfoByExceptionInfo(ExceptionInfo exceptionInfo, MaintenanceInfo maintenanceInfo) {
        /**
         * 取得当前状态
         */
        NewState newState = new NewState(this, maintenanceService);
        newState.setMaintenanceSmallInfo(maintenanceInfo);

        //处理new state 阶段该处理的事情
        newState.handleException(exceptionInfo);
        //进入下一个阶段
        newState.nextStep(exceptionInfo);

    }

    @Override
    public void saveExceptionInfo(ExceptionInfo exceptionInfo) {
        exceptionInfoRepository.save(exceptionInfo);
    }

    @Override
    public void updateExceptionInfo(ExceptionInfo exceptionInfo) {
//        exceptionInfoRepositroy.(exceptionInfo);

    }

    @Override
    public ExceptionInfo findByid(Long id) {
        Optional<ExceptionInfo> exceptionInfo = exceptionInfoRepository.findById(id);
        return exceptionInfo.get();
    }

    @Override
    public Long exceptionInfoDashboard() {
       return exceptionInfoRepository.count((Root<ExceptionInfo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder)->{

            List<Predicate> list = new ArrayList<>();
            LocalDate localDate = LocalDate.now();
            LocalDateTime minTime = localDate.atTime(LocalTime.MIN);
            LocalDateTime maxTime = localDate.atTime(LocalTime.MAX);
            Predicate timeQuery = criteriaBuilder.and(criteriaBuilder.between(root.get("createTime"),DateUtil.localDateTime2Date(minTime) , DateUtil.localDateTime2Date(maxTime)));
            list.add(timeQuery);
            Predicate[] p = list.toArray(new Predicate[0]);
            return criteriaBuilder.and(p);
        });
    }

    @Override
    public List<ExceptionInfo> exceptionInfoForEnterprise() {
        /**
         * Description 获取当天异常
         * Version 1.0 
         * Date 2020/3/29 10:51 下午 
         * Author howard
         * @param
         * @return java.util.List<com.tinyseed.emcp.api.exception.entity.ExceptionInfo>
         */
        return exceptionInfoRepository.findAll((Root<ExceptionInfo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) -> {

            List<Predicate> list = new ArrayList<>();
            LocalDate localDate = LocalDate.now();
            LocalDateTime minTime = localDate.atTime(LocalTime.MIN);
            LocalDateTime maxTime = localDate.atTime(LocalTime.MAX);
            Predicate timeQuery = criteriaBuilder.and(criteriaBuilder.between(root.get("createTime"), DateUtil.localDateTime2Date(minTime), DateUtil.localDateTime2Date(maxTime)));
            list.add(timeQuery);
//
            criteriaQuery.groupBy(root.get("id"), root.get("enterpriseName"));
            Predicate[] p = list.toArray(new Predicate[0]);
            return criteriaBuilder.and(p);
        });
    }

    @Override
    public Multimap<String, ExceptionInfo> getEnterpriseExceptionInfoMap() {
        /**
         * Description 获取当天异常的multimap,根据公司名称为key
         * Version 1.0 
         * Date 2020/3/29 10:51 下午 
         * Author howard
         * @param
         * @return com.google.common.collect.Multimap<java.lang.String, com.tinyseed.emcp.api.exception.entity.ExceptionInfo>
         */
        List<ExceptionInfo> exceptionInfos = this.exceptionInfoForEnterprise();
        Multimap<String, ExceptionInfo> enterpriseMap = ArrayListMultimap.create();
        exceptionInfos.forEach(item -> {
            enterpriseMap.put(item.getEnterpriseName(), item);
        });
        return enterpriseMap;
    }

    public Multimap<String, ExceptionInfo> getEnterpriseExceptionInfoMap(List<ExceptionInfo> exceptionInfos) {
        /**
         * Description 获取当天异常的multimap,根据公司名称为key
         * Version 1.0
         * Date 2020/3/29 10:51 下午
         * Author howard
         * @param
         * @return com.google.common.collect.Multimap<java.lang.String, com.tinyseed.emcp.api.exception.entity.ExceptionInfo>
         */
        Multimap<String, ExceptionInfo> enterpriseMap = ArrayListMultimap.create();
        exceptionInfos.forEach(item -> {
            enterpriseMap.put(item.getEnterpriseName(), item);
        });
        return enterpriseMap;
    }

    @Override
    public Multimap<Long, ExceptionInfo> getMonitorMapByExceptionInfo() {
        /**
         * Description 获取异常涉及产污染监测点的数量
         * Version 1.0
         * Date 2020/3/29 11:18 下午
         * Author howard
         * @param
         * @return com.google.common.collect.Multimap<java.lang.Long, com.tinyseed.emcp.api.exception.entity.ExceptionInfo>
         */
        List<ExceptionInfo> exceptionInfos = this.exceptionInfoForEnterprise();
        Multimap<Long, ExceptionInfo> enterpriseMap = ArrayListMultimap.create();
        exceptionInfos.forEach(item -> {
            enterpriseMap.put(item.getMonitorId(), item);
        });
        return enterpriseMap;
    }

    public Multimap<Long, ExceptionInfo> getMonitorMapByExceptionInfo(List<ExceptionInfo> exceptionInfos) {
        /**
         * Description 获取异常涉及产污染监测点的数量
         * Version 1.0
         * Date 2020/3/29 11:18 下午
         * Author howard
         * @param
         * @return com.google.common.collect.Multimap<java.lang.Long, com.tinyseed.emcp.api.exception.entity.ExceptionInfo>
         */
        Multimap<Long, ExceptionInfo> enterpriseMap = ArrayListMultimap.create();
        exceptionInfos.forEach(item -> {
            enterpriseMap.put(item.getMonitorId(), item);
        });
        return enterpriseMap;
    }


    @Override
    public Multimap<String, ExceptionInfo> getOrganizeGroupByExceptionInfos() {
        /**
         * Description 获取按照县区分类的异常
         * Version 1.0 
         * Date 2020/3/29 11:26 下午 
         * Author howard
         * @param
         * @return com.google.common.collect.Multimap<java.lang.String, com.tinyseed.emcp.api.exception.entity.ExceptionInfo>
         */
        List<ExceptionInfo> exceptionInfos = this.exceptionInfoForEnterprise();
        Multimap<String, ExceptionInfo> enterpriseMap = ArrayListMultimap.create();
        exceptionInfos.forEach(item -> {

            enterpriseMap.put(organizeService.getOrganizeParent(item.getOrganizeName()), item);
        });
        return enterpriseMap;
    }

    public Multimap<String, ExceptionInfo> getOrganizeGroupByExceptionInfos(List<ExceptionInfo> exceptionInfos) {
        /**
         * Description 获取按照县区分类的异常
         * Version 1.0
         * Date 2020/3/29 11:26 下午
         * Author howard
         * @param
         * @return com.google.common.collect.Multimap<java.lang.String, com.tinyseed.emcp.api.exception.entity.ExceptionInfo>
         */
        Multimap<String, ExceptionInfo> enterpriseMap = ArrayListMultimap.create();
        exceptionInfos.forEach(item -> {

            enterpriseMap.put(organizeService.getOrganizeParent(item.getOrganizeName()), item);
        });
        return enterpriseMap;
    }


    @Override
    public Multimap<String, ExceptionInfo> getOrganizeChildGroupByExceptionInfos() {
        /**
         * Description 获取个乡镇的排行
         * Version 1.0
         * Date 2020/3/29 11:28 下午
         * Author howard
         * @param
         * @return com.google.common.collect.Multimap<java.lang.Long, com.tinyseed.emcp.api.exception.entity.ExceptionInfo>
         */
        List<ExceptionInfo> exceptionInfos = this.exceptionInfoForEnterprise();
        Multimap<String, ExceptionInfo> enterpriseMap = ArrayListMultimap.create();
        exceptionInfos.forEach(item -> {

            enterpriseMap.put(item.getOrganizeName(), item);
        });
        return enterpriseMap;
    }

    public Multimap<String, ExceptionInfo> getOrganizeChildGroupByExceptionInfos( List<ExceptionInfo> exceptionInfos) {
        /**
         * Description 获取个乡镇的排行
         * Version 1.0
         * Date 2020/3/29 11:28 下午
         * Author howard
         * @param
         * @return com.google.common.collect.Multimap<java.lang.Long, com.tinyseed.emcp.api.exception.entity.ExceptionInfo>
         */
        Multimap<String, ExceptionInfo> enterpriseMap = ArrayListMultimap.create();
        exceptionInfos.forEach(item -> {

            enterpriseMap.put(item.getOrganizeName(), item);
        });
        return enterpriseMap;
    }



    @Override
    public DailyExceptionInfo getDailyException(){
        List<ExceptionInfo> exceptionInfos = this.exceptionInfoForEnterprise();
        //获取企业异常
        Multimap enterpriseMultimap = getEnterpriseExceptionInfoMap(exceptionInfos);
        Multimap monitorMultimap = getMonitorMapByExceptionInfo(exceptionInfos);

        return DailyExceptionInfo.builder()
                .enterpriseExceptionCount(enterpriseMultimap.asMap().size())
                .monitoryExceptionCount(monitorMultimap.asMap().size())
                .exceptionInfoCount(exceptionInfos.size())
                .build();
    }

    @Override
    public void saveDailyExceptionInfo(){
        dailyExceptionInfoRepository.save(getDailyException());
    }

    @Override
    public  DailyExceptionInfo getYesterdayExceptionInfo(){
        return dailyExceptionInfoRepository.findTopByOrderByIdDesc();
    }

}
